package control;
import input.KeyBoard;
import input.Mouse;

import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import javax.swing.*;

import view.Screen;
import view.UserInterface;

import model.*;

import com.sun.awt.*;

/**
 * Controller class. Handles all controlling. Yes.
 * (It really does)
 * @author Tim Cocu 
 */
public class Controller implements Runnable
{
	private static final int SCREEN_WIDTH = 1280;
	private static final int SCREEN_HEIGHT = 720;
	
	private static final double MAX_UPDATES = 60.0;
	
	private boolean running; 
	private Thread thread;
	
	private KeyBoard keyBoard;
	private Mouse mouse;
	
	private UserInterface userInterface;
	private Screen gameScreen;
	
	private Model model;
	
	private int iUpdatesLastSecond, iFramesLastSecond;
	
	/**
	 * TODO IMPORTANT ENTRY
	 * MAIN ENTRY POINT FOR THE ENTIRE PROGRAM
	 * @param args Main arguments.
	 */
	public static void main(String[] args)
	{     
		Controller controller = new Controller();
		controller.start();
	}
	
	/**
	 * Constructor for instances of the Controller class.
	 */
	public Controller()
	{
		running = false;
		model = new Model(SCREEN_WIDTH, SCREEN_HEIGHT);
		
		userInterface = new UserInterface(this, model);
		
		//CREATE WORLD
		World world = new World(SCREEN_WIDTH * 5, SCREEN_HEIGHT * 5);
		model.setWorld(world);
	}
	
	/**
	 * Method that stops both the loop and the game thread.
	 */
	public synchronized void stop()
	{
		running = false;
		
		try
		{
			thread.join();
		}
		catch(InterruptedException e) { e.printStackTrace(); }
	}
	
	/**
	 * Method for starting the game thread.
	 */
	public synchronized void start()
	{
		running = true;
		thread = new Thread(this, "Display");
		thread.start();
	}

	/**
	 * Run method.
	 */
	public void run() 
	{
		long lLastTime = System.nanoTime();
		long lTimer = System.currentTimeMillis();
		final double dNanoSeconds = 1000000000.0 / MAX_UPDATES;
		double dDelta = 0;
		
		int iFrames = 0;
		int iUpdates = 0;
		
		while(running)
		{
			long lLoopStart = System.nanoTime();
			
			dDelta += (lLoopStart - lLastTime) / dNanoSeconds;
			lLastTime = lLoopStart;
			
			while(dDelta >= 1)
			{
				update();
				iUpdates++;

				dDelta--;
			}

			render();
			iFrames++;
			
			if(System.currentTimeMillis() - lTimer > 1000)
			{
				lTimer += 1000;
				this.iUpdatesLastSecond = iUpdates;
				this.iFramesLastSecond = iFrames;

				iFrames = iUpdates = 0;
			}		
		}
		
		stop();
	}
	
	/**
	 * Method that handles all updates.
	 * ALL THE UPDATES.
	 */
	public void update()
	{
		model.getWorld().update();
		userInterface.update();
	}
	
	/**
	 * Method that handles all rendering.
	 * ALL THE RENDERING.
	 */
	public void render()
	{
		userInterface.render(iFramesLastSecond, iUpdatesLastSecond);
	}
}
